#include "sql_connection_pool.hpp"

ConnectionPool::ConnectionPool()
{
    m_CurConn = 0;
    m_FreeConn = 0;
}

ConnectionPool::~ConnectionPool()
{
    DestoryPool();
}

ConnectionPool* ConnectionPool::GetInstance()
{
    static ConnectionPool connPool;
    return &connPool;
}

void ConnectionPool::Init(string _url,string _usr,string _passWord,string _dataBaseName,int _port,unsigned int _maxCount)
{
    this->m_url = _url;
    this->m_user = _usr;
    this->m_password = _passWord;
    this->m_dataBaseName = _dataBaseName;
    this->m_port = _port;

    // 初始化所有的sql连接池
    m_lock.Lock();
    for(size_t i = 0;i<_maxCount;++i)
    {
        MYSQL* con = nullptr;
        con = mysql_init(con);
        if(con==nullptr)
        {
            printf("init Error:%s\n",mysql_error(con));
            exit(-1);
        }
        con = mysql_real_connect(con,m_url.c_str(),m_user.c_str(),m_password.c_str(),m_dataBaseName.c_str(),m_port,NULL,0);
        if(con==nullptr)
        {
            printf("Connect Error:%s\n",mysql_error(con));
            exit(-1);        
        }
        m_connList.push_back(con);
        ++m_FreeConn;
        printf( "create MySQL [%d]\n", i );
    }
    m_sem = Sem(m_FreeConn);
    m_MaxConn = _maxCount;
    m_lock.UnLock();
}

MYSQL* ConnectionPool::GetConnect()
{
    MYSQL* conn = NULL;
    if(this->m_connList.size() == 0)
    {
        return NULL;
    }
    this->m_sem.Wait(); // 信号量，初始值为整个空闲队列，当所有队列都处于忙碌状态则阻塞
    this->m_lock.Lock();

    conn = m_connList.front();
    m_connList.pop_back();

    --m_FreeConn;
    ++m_CurConn;

    this->m_lock.UnLock();
    return conn;
}

bool ConnectionPool::ReleaseConnection(MYSQL* _conn)
{
    if(_conn == NULL)
    {
        return false;
    }
    m_lock.Lock();

    m_connList.push_back(_conn);
    ++m_FreeConn;
    --m_CurConn;

    m_lock.UnLock();

    m_sem.Post();
    return true;
}

const int ConnectionPool::GetFreeConn() const 
{
    return m_FreeConn;
}

void ConnectionPool::DestoryPool()
{
    m_lock.Lock();
    if(m_connList.size() > 0)
    {
        auto iter = m_connList.begin();
        for(;iter!=m_connList.end();++iter)
        {
            MYSQL* con = *iter;
            mysql_close(con);
        }
        m_CurConn = 0;
        m_FreeConn = 0;
        m_connList.clear();

        m_lock.UnLock();
    }
    m_lock.UnLock();
}

ConnectionRALL::ConnectionRALL(MYSQL** _conn,ConnectionPool* _pool)
{
    *_conn = _pool->GetConnect();

    m_connRALL = *_conn;
    m_poolRALL = _pool;
}

ConnectionRALL::~ConnectionRALL()
{
    m_poolRALL->ReleaseConnection(m_connRALL);
}